package business

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	common "example.com/m/com.common"
	qfcfg "example.com/m/com.qfcfg"
	qfcrypt "example.com/m/com.qfcrypt"
	qflog "example.com/m/com.qflog"
	qfmysql "example.com/m/com.qfmysql"
	qfredis "example.com/m/com.qfredis"
	"example.com/m/com.xorm_models/models"
	"github.com/gin-gonic/gin"
	"github.com/go-basic/uuid"
	_ "github.com/go-sql-driver/mysql"
)

// const def
const (
	LockedTimes int = 7
	LockedPeriod int64 = 30 * 60 
)

// JSONResult def
type JSONResult struct {
	Status int    `json:"status"`
	Data   string `json:"data"`
}

// Controller def
type Controller struct {
}

// CheckTraceID def
func (control Controller) CheckTraceID(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	if traceID == "" {
		uid := uuid.New()
		tmpSlice := strings.Split(uid, "-")
		slicelen := len(tmpSlice)
		traceID = tmpSlice[slicelen-1]
		c.Request.Header.Set(common.TraceID, traceID)
		qflog.Sugare.Warnf("Request generate trace id:%s, uri:%s method:%s", traceID, c.Request.RequestURI, c.Request.Method)
		// return uuid
	}
	c.Writer.Header().Set(common.TraceID, traceID)
}

// check json data
func checkJSONData(c *gin.Context) bool {
	traceID := c.Request.Header.Get(common.TraceID)
	// 解析form
	err := c.Request.ParseForm()
	if err != nil {
		qflog.Sugare.Errorf("TraceID=%s|Parse form error:", traceID, err)
		return false
	}

	// 判断消息体是否是application/json
	isJSON := false
	for _, v := range c.Request.Header["Content-Type"] {
		if strings.Index(v, "application/json") != -1 {
			isJSON = true
		}
	}

	if !isJSON {
		qflog.Sugare.Errorf("TraceID=%s|Content-Type invalid, is:%s", traceID, c.Request.Header["Content-Type"])
		return false
	}

	return true
}

// sendJSONResp def
func sendJSONResp(c *gin.Context, msg string, status int) {
	traceID := c.Writer.Header().Get(common.TraceID)
	retMsg, _ := json.Marshal(JSONResult{Status: status, Data: msg})
	c.JSON(http.StatusOK, JSONResult{Status: status, Data: msg})
	qflog.Sugare.Infof("TraceID=%s|response data:%s", traceID, string(retMsg))
}

// get remote ip
func getRemoteIP(req *http.Request) (string, string) {
	remoteAddr := req.RemoteAddr
	port := "0"
	if ip := req.Header.Get("X-Real-IP"); ip != "" {
		remoteAddr = ip
	} else if ip = req.Header.Get("X-Forwarded-For"); ip != "" {
		remoteAddr = ip
	} else {
		remoteAddr, port, _ = net.SplitHostPort(remoteAddr)
	}

	if remoteAddr == "::1" {
		remoteAddr = "127.0.0.1"
	}

	return remoteAddr, port
}

// write log to db
func writeLogToDB(c *gin.Context, majorType string, minorType string, optUser string, msg string) {
	traceID := c.Request.Header.Get(common.TraceID)
	remoteIP, port := getRemoteIP(c.Request)
	ipInfo := fmt.Sprintf("%s:%s", remoteIP, port)
	ipInfoBase64Tmp := base64.StdEncoding.EncodeToString([]byte(ipInfo))
	sessionID := strings.Replace(ipInfoBase64Tmp, "=", "", -1)
	nowTime := time.Now().Format(common.TimeFormatCMT) //time转string

	var logInfo models.TLogInfo
	logInfo.VSessionId = sessionID
	logInfo.VMajorType = majorType
	logInfo.VMinorType = minorType
	logInfo.VOptUser = optUser
	logInfo.VClientIp = remoteIP
	logInfo.VOptTime = nowTime
	logInfo.VOptInfo = msg
	_, _ = qfmysql.InsertLogInfo(c, logInfo)
	qflog.Sugare.Infof("TraceID=%s|major opt:%s, minor opt:%s, username:%s, %s, client addr:%s", traceID, majorType, minorType, optUser, msg, ipInfo)
}

// calculate hash
func calculateHash(toBeHashed string) string {
	hashInBytes := sha256.Sum256([]byte(toBeHashed))
	hashStr := hex.EncodeToString(hashInBytes[:])
	return hashStr
}

// check and trans request data
func checkAndTransReqData(c *gin.Context) map[string]string {
	traceID := c.Request.Header.Get(common.TraceID)
	// 用于存放参数key=value数据
	var reqParams map[string]string
	reqParams = make(map[string]string)
	uri := c.Request.RequestURI
	if c.Request.Method != "POST" {
		c.Writer.WriteHeader(http.StatusNotFound)
		qflog.Sugare.Errorf("TraceID=%s|404", traceID)
		return reqParams
	}

	ret := checkJSONData(c)
	if ret == false {
		qflog.Sugare.Errorf("TraceID=%s|Check json data invalid.", traceID)
		c.Writer.WriteHeader(http.StatusBadRequest)
		qflog.Sugare.Errorf("TraceID=%s|404", traceID)
		return reqParams
	}

	decoder := json.NewDecoder(c.Request.Body)
	// 解析参数 存入map
	decoder.Decode(&reqParams)
	mJSON, _ := json.Marshal(reqParams)
	dataStr := string(mJSON)
	qflog.Sugare.Infof("TraceID=%s|uri:%s method:%s, request data:%s", traceID, uri, c.Request.Method, dataStr)
	return reqParams
}

// AuthHandler http
func (control Controller) AuthHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	var params map[string]string
	params = checkAndTransReqData(c)
	if len(params) == 0 {
		qflog.Sugare.Errorf("TraceID=%s|Check and trans request data failed.", traceID)
		return
	}

	var pwd string

	userInfo, err := qfmysql.QueryUserInfo(c, params["username"])
	if err != nil {
		qflog.Sugare.Errorf("TraceID=%s|username:%s noexist", traceID, params["username"])
		optInfo := fmt.Sprintf("登录失败, 用户不存在, PC-NAME: %s, %s", params["pcname"], params["ip"])
		writeLogToDB(c, "操作", "远程登录", params["username"], optInfo)
		sendJSONResp(c, "noexist", 200)
		return
	}

	// name = userInfo.UName
	pwd = userInfo.UPwd
	qflog.Sugare.Infof("TraceID=%s|username:%s info: %+v", traceID, params["username"], *userInfo)

	// 判断用户是否锁定
	errCnt := userInfo.UErrorCnt
	lastLockedTime := userInfo.ULockedTime

	if errCnt >= LockedTimes {
		if lastLockedTime != "" {
			now := time.Now()               //已知的时间戳
			ts := now.Format(common.TimeFormatCMT) //time转string
			formatTime, err := time.Parse(common.TimeFormatCMT, lastLockedTime)
			nowTime, err := time.Parse(common.TimeFormatCMT, ts)
			if err != nil {
				qflog.Sugare.Errorf("TraceID=%s|error:", traceID, err)
			}

			remainPeriod := LockedPeriod - int64(nowTime.Sub(formatTime).Seconds())
			if remainPeriod > 0 {
				remainPeriodM := remainPeriod / 60
				remainPeriodS := remainPeriod % 60
				optInfo := fmt.Sprintf("被锁定, %dm%ds后解锁, PC-NAME: %s, %s", remainPeriodM, remainPeriodS, params["pcname"], params["ip"])
				writeLogToDB(c, "操作", "远程登录", params["username"], optInfo)
				dataInfo := fmt.Sprintf("locked,%dm%ds", remainPeriodM, remainPeriodS)
				sendJSONResp(c, dataInfo, 200)
				return
			}

			// 已超过锁定时长， 清空错误次数和锁定时间点
			errCnt = 0
			nowTmpTime := ""

			var useInfo models.TUser
			useInfo.UName = params["username"]
			useInfo.UErrorCnt = errCnt
			useInfo.ULockedTime = nowTmpTime
			_, _ = qfmysql.UpdateUserInfo(c, useInfo)
		}
	}

	// 登录密码验证
	// 后台支持http_login摘要认证(SHA256)和密码鉴权
	nonceIsOk := false
	pwdIsOk := false

	pwdNonce1 := params["pwd"]

	plainData := fmt.Sprintf("%s#qinfengjishu#%s", pwd, params["random"])
	pwdNonce2 := calculateHash(plainData)

	// 摘要认证，重新计算SHA256摘要
	if pwdNonce1 == pwdNonce2 {
		nonceIsOk = true
	}

	// 普通密码验证
	if pwdNonce1 == pwd {
		pwdIsOk = true
	}

	retVal := checkWsseSimple(c, params, traceID)
	if retVal != "pass" {
		qflog.Sugare.Errorf("TraceID=%s|check wsse: %s.", traceID, retVal)
		nonceIsOk = false
	} else {
		nonceIsOk = true
	}

	qflog.Sugare.Infof("TraceID=%s|pwdNonce1:%s, pwdNonce2:%s, wsse retVal:%s nonceIsOk:%v pwdIsOk:%v", traceID, pwdNonce1, pwdNonce2, retVal, nonceIsOk, pwdIsOk)

	if nonceIsOk || pwdIsOk {
		// 清空错误次数和锁定时间点
		errCnt = 0
		nowTmpTime := ""
		var useInfo models.TUser
		useInfo.UName = params["username"]
		useInfo.UErrorCnt = errCnt
		useInfo.ULockedTime = nowTmpTime
		_, _ = qfmysql.UpdateUserInfo(c, useInfo)

		optInfo := fmt.Sprintf("登录成功, PC-NAME: %s, %s", params["pcname"], params["ip"])
		writeLogToDB(c, "操作", "远程登录", params["username"], optInfo)
		sendJSONResp(c, "pass", 200)
		return
	} else {
		// 密码错误，更新错误次数和尝试登录时间
		errCnt++
		nowTmpTime := time.Now().Format(common.TimeFormatCMT)
		var useInfo models.TUser
		useInfo.UName = params["username"]
		useInfo.UErrorCnt = errCnt
		useInfo.ULockedTime = nowTmpTime
		_, _ = qfmysql.UpdateUserInfo(c, useInfo)

		// 累计达到7次错误， 提示锁定
		if errCnt >= LockedTimes {
			remainPeriod := LockedPeriod
			remainPeriodM := remainPeriod / 60
			remainPeriodS := remainPeriod % 60
			optInfo := fmt.Sprintf("被锁定, %dm%ds后解锁, PC-NAME: %s, %s", remainPeriodM, remainPeriodS, params["pcname"], params["ip"])
			writeLogToDB(c, "操作", "远程登录", params["username"], optInfo)
			dataInfo := fmt.Sprintf("locked,%dm%ds", remainPeriodM, remainPeriodS)
			sendJSONResp(c, dataInfo, 200)
			return
		}

		// 未锁定， 提示密码错误
		optInfo := fmt.Sprintf("登录失败, 密码错误, PC-NAME %s, %s", params["pcname"], params["ip"])
		writeLogToDB(c, "操作", "远程登录", params["username"], optInfo)
		sendJSONResp(c, "error", 200)
	}
}

// path file existt
func pathFileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		// qflog.Sugare.Infof("file:%s exist.", path)
		return true, nil
	}
	if os.IsNotExist(err) {
		// qflog.Sugare.Errorf("file:%s not exist.", path)
		return false, err
	}
	return false, err
}

// RSADecrypt def
// cipherText 需要解密的byte数据
// path 私钥文件路径
func RSADecrypt(cipherText []byte, path string) []byte {
	//打开文件
	file, err := os.Open(path)
	if err != nil {
		qflog.Sugare.Errorf("err: %v", err)
	}
	defer file.Close()
	//获取文件内容
	info, _ := file.Stat()
	buf := make([]byte, info.Size())
	file.Read(buf)
	//pem解码
	block, _ := pem.Decode(buf)
	//X509解码
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		qflog.Sugare.Errorf("err: %v", err)
	}
	//对密文进行解密
	plainText, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
	//返回明文
	return plainText
}

// RegistHandler http
func (control Controller) RegistHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	var params map[string]string
	params = checkAndTransReqData(c)
	if len(params) == 0 {
		qflog.Sugare.Errorf("TraceID=%s|Check and trans request data failed.", traceID)
		return
	}

	level := "游客"
	username := params["username"]
	pcname := params["pcname"]

	// 返回RSA加密公钥
	opt, ok := params["opt"]
	algorithm, ok1 := params["algorithm"]
	if ok && ok1 {
		if opt == "queryPubkey" && algorithm == "RSA" {
			pubKeyCertPth := "./pem/rsa_public_key.pem"
			existFalg, _ := pathFileExists(pubKeyCertPth)
			if !existFalg {
				optInfo := fmt.Sprintf("注册失败, RSA公钥证书不存在, PC-NAME: %s", pcname)
				writeLogToDB(c, "操作", "用户注册", username, optInfo)
				sendJSONResp(c, "pub_key_cert_not_exist", 200)
				return
			}

			f, err := os.Open(pubKeyCertPth)
			if err != nil {
				qflog.Sugare.Errorf("TraceID=%s|error: %v", traceID, err)
				return
			}
			defer func() {
				f.Close()
			}()
			pubKeyCert, _ := ioutil.ReadAll(f)
			sendJSONResp(c, string(pubKeyCert), 200)
			return
		}
	}

	// 查询用户是否存在
	_, err := qfmysql.QueryUserInfo(c, username)
	if err == nil {
		optInfo := fmt.Sprintf("注册失败, 用户已存在, PC-NAME:%s", pcname)
		writeLogToDB(c, "操作", "远程登录", username, optInfo)
		sendJSONResp(c, "exist", 200)
		return
	}

	// 兼容客户端是否使用密码加密算法/RSA
	decryptPwd := ""
	if algorithm == "RSA" {
		encryptPwdTmp := params["pwd"] // 传输过来的已base64编码

		// RSA私钥解密
		priKeyCertPth := "./pem/rsa_private_key.pem"
		existFalg, _ := pathFileExists(priKeyCertPth)
		if !existFalg {
			optInfo := fmt.Sprintf("注册失败, RSA私钥证书不存在, PC-NAME: %s", pcname)
			writeLogToDB(c, "操作", "用户注册", username, optInfo)
			sendJSONResp(c, "pri_key_cert_not_exist", 200)
			return
		}

		encryptPwdReal := strings.Replace(encryptPwdTmp, "%2B", "+", -1)
		// 对上面的编码结果进行base64解码
		decodeBytes, err := base64.StdEncoding.DecodeString(encryptPwdReal)
		if err != nil {
			qflog.Sugare.Errorf("TraceID=%s|error: %v", traceID, err)
		}
		decryptPwdBytes := RSADecrypt(decodeBytes, priKeyCertPth)
		decryptPwd = string(decryptPwdBytes)
		qflog.Sugare.Infof("TraceID=%s|decryptPwd: %s", traceID, decryptPwd)
		if decryptPwd == "" {
			optInfo := fmt.Sprintf("注册失败, 注册密码RSA解密失败, PC-NAME: %s", pcname)
			writeLogToDB(c, "操作", "用户注册", username, optInfo)
			sendJSONResp(c, "pwd_decrypt_fail", 200)
			return
		}
	} else {
		decryptPwd = params["pwd"]
	}

	var userInfo models.TUser
	userInfo.UName = username
	userInfo.UPwd = decryptPwd
	userInfo.ULevel = level
	userInfo.UErrorCnt = 0
	userInfo.ULockedTime = ""
	_, err = qfmysql.InsertUserInfo(c, userInfo)
	if err == nil {
		optInfo := fmt.Sprintf("注册成功, PC-NAME: %s", pcname)
		writeLogToDB(c, "操作", "用户注册", username, optInfo)
		sendJSONResp(c, "succeed", 200)
	} else {
		optInfo := fmt.Sprintf("注册失败, 未知错误, PC-NAME: %s", pcname)
		writeLogToDB(c, "操作", "用户注册", username, optInfo)
		sendJSONResp(c, "failed", 200)
	}
}

var binPath string = ""

// checkWsse def
func checkWsse(c *gin.Context) string {
	traceID := c.Request.Header.Get(common.TraceID)
	wsseMap := map[string]string{"Username": "", "PasswordDigest": "", "Nonce": "", "Created": ""}
	if qfcfg.ServerConfig.Server.Auth.Enable == 0 {
		return "pass"
	}

	wsseInfo := c.Request.Header.Get("X-WSSE")
	if wsseInfo == "" {
		return "wsse check failed"
	}

	token := strings.Split(wsseInfo, " ")[0]
	if token != "UsernameToken" {
		return "wsse check failed"
	}

	pos := strings.Index(wsseInfo, token)
	wsseStr := string(wsseInfo[pos+len(token):])
	wsseList := strings.Split(wsseStr, ",")
	for _, item := range wsseList {
		item = strings.Trim(item, " ")
		itemList := strings.Split(item, "=")
		_, ok := wsseMap[itemList[0]]
		if ok {
			wsseMap[itemList[0]] = strings.Trim(itemList[1], "\"")
		}
	}

	for wsseKey := range wsseMap {
		if wsseMap[wsseKey] == "" {
			qflog.Sugare.Errorf("TraceID=%s|wsse header:%s is blank", traceID, wsseKey)
			return "wsse check failed"
		}
	}

	mJSON, _ := json.Marshal(wsseMap)
	wsseData := string(mJSON)
	qflog.Sugare.Infof("TraceID=%s|wsse data: %s", traceID, wsseData)

	username := wsseMap["Username"]
	digest := wsseMap["PasswordDigest"]
	nonce := wsseMap["Nonce"]
	created := wsseMap["Created"]

	createdTime, err := time.Parse("2006-01-02T15:04:05Z", created)
	if err != nil {
		qflog.Sugare.Errorf("TraceID=%s|err: %s", traceID, err)
	}
	// createdTmpTime := createdTime.Format("2006-01-02 15:04:05")
	nowTmpTime := time.Now().Format(common.TimeFormatCMT) //time转string
	nowTime, _ := time.Parse(common.TimeFormatCMT, nowTmpTime)

	delta := int64(nowTime.Sub(createdTime).Seconds())
	if delta > int64(qfcfg.ServerConfig.Server.Auth.Redis.Timeout) {
		qflog.Sugare.Errorf("TraceID=%s|created: %s out time, now time:%s, delta:%d.", traceID, created, nowTmpTime, delta)
		return "outtime"
	}

	// 查询用户是否存在
	userInfo, err := qfmysql.QueryUserInfo(c, username)
	if err != nil {
		qflog.Sugare.Errorf("TraceID=%s|user:%s noxist. err: %v", traceID, username, err)
		return "noexist"
	}
	password := userInfo.UPwd

	// sha256鉴权
	plainData := fmt.Sprintf("%s%s%s%s", username, password, nonce, created)
	digestCal := calculateHash(plainData)
	if digest != digestCal {
		qflog.Sugare.Errorf("TraceID=%s|PasswordDigest: %s error.", traceID, digest)
		return "error"
	}

	val, err := qfredis.GetDigestInfo(c, digest)
	if err == nil {
		qflog.Sugare.Errorf("TraceID=%s|repeat digest: %s error, val: %s.", traceID, digest, val)
		return "repeat digest"
	}

	err = qfredis.SetDigestInfo(c, digest, "1", qfcfg.ServerConfig.Server.Auth.Redis.Timeout)
	if err != nil {
		qflog.Sugare.Errorf("TraceID=%s|error: %v", traceID, err)
	}

	return "pass"
}

func checkWsseSimple(c *gin.Context, params map[string]string, traceID string) string {
	if len(params) == 0 {
		qflog.Sugare.Errorf("TraceID=%s|Check and trans request data failed.", traceID)
		return "wsse check failed"
	}

	timestamp, ok := params["timestamp"]
	var timeVal int64
	if ok {
		timeTmp, _ := strconv.Atoi(timestamp)
		timeVal = int64(timeTmp)
		nowTime := time.Now().Unix()

		if timeVal-nowTime > int64(qfcfg.ServerConfig.Server.Auth.Redis.Timeout) ||
			nowTime-timeVal > int64(qfcfg.ServerConfig.Server.Auth.Redis.Timeout) {
			qflog.Sugare.Errorf("TraceID=%s|created: %v out time, now time:%v, timeout:%d.", traceID, timeVal, nowTime, qfcfg.ServerConfig.Server.Auth.Redis.Timeout)
			return "outtime"
		}

		pwd, _ := params["pwd"]
		random, _ := params["random"]
		username, _ := params["username"]

		// 查询用户是否存在
		userInfo, err := qfmysql.QueryUserInfo(c, username)
		if err != nil {
			qflog.Sugare.Errorf("TraceID=%s|user:%s noxist. err: %v", traceID, username, err)
			return "noexist"
		}
		password := userInfo.UPwd

		// sha256鉴权
		plainData := fmt.Sprintf("%s%s%s%s", username, password, random, timestamp)
		digestCal := calculateHash(plainData)
		if pwd != digestCal {
			qflog.Sugare.Errorf("TraceID=%s|PasswordDigest: %s error.", traceID, pwd)
			return "error"
		}

		val, err := qfredis.GetDigestInfo(c, pwd)
		if err == nil {
			qflog.Sugare.Errorf("TraceID=%s|repeat digest: %s error, val: %s.", traceID, pwd, val)
			return "repeat digest"
		}

		err = qfredis.SetDigestInfo(c, pwd, "1", qfcfg.ServerConfig.Server.Auth.Redis.Timeout)
		if err != nil {
			qflog.Sugare.Errorf("TraceID=%s|error: %v", traceID, err)
		}

		return "pass"
	}

	return "pass"
}

// EncryptHandler def
func (control Controller) EncryptHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)

	var params map[string]string
	params = checkAndTransReqData(c)
	if len(params) == 0 {
		qflog.Sugare.Errorf("TraceID=%s|Check and trans request data failed.", traceID)
		return
	}

	//"hello cava3"
	plainText := params["data"]

	encData, err := qfcrypt.ConfigAes.Encrypt([]byte(plainText), params["version"])
	if err != nil {
		dataInfo := fmt.Sprintf("TraceID=%s|encrypt err: %v", traceID, err)
		qflog.Sugare.Errorf(dataInfo)
		sendJSONResp(c, dataInfo, 200)
		return
	}

	qflog.Sugare.Infof("TraceID=%s|encrypt data: %s", traceID, encData)
	sendJSONResp(c, encData, 200)
}

// DecryptHandler def
func (control Controller) DecryptHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)

	var params map[string]string
	params = checkAndTransReqData(c)
	if len(params) == 0 {
		qflog.Sugare.Errorf("TraceID=%s|Check and trans request data failed.", traceID)
		return
	}

	//"hello cava3"
	encData := params["data"]

	qflog.Sugare.Infof("TraceID=%s|encData data: %s", traceID, encData)
	decData, err := qfcrypt.ConfigAes.Decrypt(encData, params["version"])
	if err != nil {
		dataInfo := fmt.Sprintf("TraceID=%s|decrypt err: %v", traceID, err)
		qflog.Sugare.Errorf(dataInfo)
		sendJSONResp(c, dataInfo, 200)
		return
	}

	decDataStr := string(decData[:])
	qflog.Sugare.Infof("TraceID=%s|decrypt data: %s", traceID, decDataStr)
	sendJSONResp(c, decDataStr, 200)
}

// UploadHandler http
func (control Controller) UploadHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	if c.Request.Method != "POST" {
		c.Writer.WriteHeader(http.StatusNotFound)
		qflog.Sugare.Errorf("TraceID=%s|404", traceID)
		return
	}

	retVal := checkWsse(c)
	if retVal != "pass" {
		qflog.Sugare.Errorf("TraceID=%s|check wsse: %s.", traceID, retVal)
		sendJSONResp(c, retVal, 200)
		return
	}

	//qfcfg.ServerConfig.Server.Auth.Redis
	if c.Request.Method == "POST" {
		//设置内存大小
		c.Request.ParseMultipartForm(32 << 20)
		//获取上传的第一个文件
		file, header, err := c.Request.FormFile("file")
		defer file.Close()
		if err != nil {
			desc := fmt.Sprintf("error: %v", err)
			qflog.Sugare.Errorf("TraceID=%s|%s", traceID, desc)
			sendJSONResp(c, desc, 200)
			return
		}

		//创建上传文件
		if binPath == "" {
			var err error
			binPath, err = os.Getwd()
			if err != nil {
				desc := fmt.Sprintf("error: %v", err)
				qflog.Sugare.Errorf("TraceID=%s|%s", traceID, desc)
				sendJSONResp(c, desc, 200)
				return
			}
			qflog.Sugare.Infof("TraceID=%s|binPath:%s", traceID, binPath)
		}

		basename := header.Filename
		filePath := binPath + "/cava3/upload/" + header.Filename
		existFalg, _ := pathFileExists(filePath)

		// 目标目录文件存在，且不强制更新，返回文件已存在
		forceUpload := c.Request.Header.Get("FORCE-UPLOAD")
		if forceUpload == "" || forceUpload == "FALSE" {
			if existFalg {
				qflog.Sugare.Infof("TraceID=%sfile exist, filePath:%s", traceID, filePath)
				sendJSONResp(c, "file exist", 200)
				return
			}
		} else if forceUpload == "TRUE" {
			if existFalg {
				err := os.Remove(filePath)
				if err != nil {
					desc := fmt.Sprintf("error: %v", err)
					qflog.Sugare.Errorf("TraceID=%s|%s", traceID, desc)
					sendJSONResp(c, desc, 200)
					return
				}
			}
		}

		// for i := 0; ; i++ {
		// 	existFalgTmp, _ := pathFileExists(filePath)
		// 	if existFalgTmp {
		// 		basename = basename + "_"
		// 		filePath = filePath + "_"
		// 	} else {
		// 		break
		// 	}
		// }

		cur, err := os.Create(filePath)
		defer cur.Close()
		if err != nil {
			desc := fmt.Sprintf("error: %v", err)
			qflog.Sugare.Errorf("TraceID=%s|%s", traceID, desc)
			sendJSONResp(c, desc, 200)
			return
		}

		qflog.Sugare.Infof("TraceID=%s|filePath:%s", traceID, filePath)
		//把上传文件数据拷贝到我们新建的文件
		io.Copy(cur, file)

		httpIP := qfcfg.ServerConfig.Server.IP
		// 如果使能了http下载文件使用IP，则使用外网IP
		if qfcfg.ServerConfig.Server.Enable != 0 {
			httpIP = qfcfg.ServerConfig.Server.WanIP
		}
		msg := fmt.Sprintf("[INFO] file:%s upload succeed, path:http://%s:%d/cava3/upload/%s",
			filePath, httpIP, qfcfg.ServerConfig.Server.Port, basename)
		sendJSONResp(c, msg, 200)
	}
}

// NoticeHandler http
func (control Controller) NoticeHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	if c.Request.Method != "GET" {
		c.Writer.WriteHeader(http.StatusNotFound)
		qflog.Sugare.Errorf("TraceID=%s|404", traceID)
		return
	}

	qflog.Sugare.Infof("TraceID=%s|uri:%s method:%s", traceID, c.Request.RequestURI, c.Request.Method)
	sendJSONResp(c, qfcfg.ServerConfig.Server.Notice, 200)
}

// DownloadHandler http
func (control Controller) DownloadHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	if c.Request.Method != "GET" {
		c.Writer.WriteHeader(http.StatusNotFound)
		qflog.Sugare.Errorf("TraceID=%s|404", traceID)
		return
	}

	if binPath == "" {
		var err error
		binPath, err = os.Getwd()
		if err != nil {
			qflog.Sugare.Errorf("TraceID=%s|error: %v", traceID, err)
		}
		qflog.Sugare.Infof("TraceID=%s|binPath:%s", traceID, binPath)
	}

	// vars := mux.Vars(r) // 获取参数
	uri := c.Request.RequestURI
	filePath := binPath + uri
	qflog.Sugare.Infof("TraceID=%s|GET filePath: %s", traceID, filePath)
	isExist, _ := pathFileExists(filePath)

	if isExist {
		//打开文件
		file, err := os.Open(filePath)
		if err != nil {
			c.Writer.WriteHeader(http.StatusBadRequest)
			return
		}
		//结束后关闭文件
		defer file.Close()

		//设置响应的header头
		c.Writer.Header().Add("Content-type", "application/octet-stream")
		c.Writer.Header().Add("content-disposition", "attachment; filename=\""+c.Param("filename")+"\"")
		//将文件写至responseBody
		_, err = io.Copy(c.Writer, file)
		if err != nil {
			c.Writer.WriteHeader(http.StatusBadRequest)
			return
		}
	} else {
		c.Writer.WriteHeader(http.StatusNotFound)
		qflog.Sugare.Errorf("TraceID=%s|404", traceID)
	}
}

// LockHandler def
func (control Controller) LockHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	// lock
	if lock := qfredis.QFCommonLocker.Lock(c); !lock {
		info := "lock has been dispatched other, please wait"
		qflog.Sugare.Errorf("TraceID=%s|%s", traceID, info)
		sendJSONResp(c, info, 200)
		// time.Sleep(10 * time.Millisecond)
		return
	}
	// do sth.
	time.Sleep(6 * time.Second)
	info := "dispatch lock to this"
	qflog.Sugare.Infof("TraceID=%s|%s", traceID, info)
	sendJSONResp(c, info, 200)

	defer qfredis.QFCommonLocker.UnLock(c)
}

// RedisHandler http
func (control Controller) RedisHandler(c *gin.Context) {
	traceID := c.Request.Header.Get(common.TraceID)
	// vars := mux.Vars(r) // 获取参数
	c.Writer.WriteHeader(http.StatusOK)

	val, err := qfredis.MembersIPInfo(c, "mts_10.8.5.161")
	if err != nil {
		qflog.Sugare.Errorf("TraceID=%s|error: %v", traceID, err)
		c.Writer.WriteHeader(http.StatusBadRequest)
		return
	}

	var value string
	for _, v := range val {
		value = v
		qflog.Sugare.Infof("TraceID=%s|value: %s", traceID, value)
	}
	info := fmt.Sprintf("value: %s\n", value)
	c.Writer.WriteString(info)
}
